import {
  Controller,
  Get,
  Post,
  Delete,
  Param,
  UseInterceptors,
  UploadedFile,
  Body,
  UseGuards,
  Request,
  ParseFilePipe,
  MaxFileSizeValidator,
  HttpStatus,
  PayloadTooLargeException,
  UnsupportedMediaTypeException,
  Query,
  Res,
  NotFoundException,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { SourcemapService } from './sourcemap.service';
import { CreateSourcemapDto } from './dto/create-sourcemap.dto';
import { LocateErrorDto } from './dto/locate-error.dto';
import { Sourcemap } from './entities/sourcemap.entity';
import { ErrorLocationVo } from './vo/error-location.vo';
import { ListSourcemapDto } from './dto/list-sourcemap.dto';
import { ListSourcemapVo } from './vo/list-sourcemap.vo';
import { Response } from 'express';
import * as fs from 'fs';
import * as path from 'path';

const MAX_FILE_SIZE = 500 * 1024 * 1024; // 500MB in bytes

@Controller('sourcemap')
export class SourcemapController {
  constructor(private readonly sourcemapService: SourcemapService) {}

  @Post('create')
  @UseInterceptors(
    FileInterceptor('file', {
      limits: {
        files: 1,
        fileSize: MAX_FILE_SIZE,
      },
      fileFilter: (req, file, callback) => {
        if (!file.originalname.toLowerCase().endsWith('.zip')) {
          return callback(
            new UnsupportedMediaTypeException('只支持上传 zip 文件'),
            false,
          );
        }
        if (file.size > MAX_FILE_SIZE) {
          return callback(
            new PayloadTooLargeException('文件大小不能超过 500MB'),
            false,
          );
        }
        callback(null, true);
      },
    }),
  )
  async upload(
    @UploadedFile(
      new ParseFilePipe({
        validators: [
          new MaxFileSizeValidator({
            maxSize: MAX_FILE_SIZE,
            message: '文件大小不能超过 500MB',
          }),
        ],
        errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,
      }),
    )
    file: Express.Multer.File,
    @Body() createSourcemapDto: CreateSourcemapDto,
    @Request() req,
  ): Promise<void> {
    await this.sourcemapService.create(file, createSourcemapDto, req.user);
  }

  @Get('error')
  async locateError(
    @Query() locateErrorDto: LocateErrorDto,
  ): Promise<ErrorLocationVo> {
    return this.sourcemapService.locateError(locateErrorDto);
  }

  @Get('list')
  async getList(
    @Query() listSourcemapDto: ListSourcemapDto,
  ): Promise<ListSourcemapVo> {
    return this.sourcemapService.getList(listSourcemapDto);
  }

  @Get()
  async findAll(): Promise<Sourcemap[]> {
    return this.sourcemapService.findAll();
  }

  @Get(':id')
  async findOne(@Param('id') id: string): Promise<Sourcemap> {
    return this.sourcemapService.findOne(+id);
  }

  @Delete(':id')
  async remove(@Param('id') id: string): Promise<void> {
    await this.sourcemapService.remove(+id);
  }

  @Get('download/:id')
  async download(@Param('id') id: string, @Res() res: Response): Promise<void> {
    const sourcemap = await this.sourcemapService.findOne(+id);

    // 如果 filepath 是相对路径，将其转换为绝对路径
    const absolutePath = path.isAbsolute(sourcemap.filepath)
      ? sourcemap.filepath
      : path.join(process.cwd(), sourcemap.filepath);

    if (!fs.existsSync(absolutePath)) {
      throw new NotFoundException('文件不存在');
    }

    // 设置响应头
    res.setHeader('Content-Type', 'application/zip');
    res.setHeader(
      'Content-Disposition',
      `attachment; filename="${encodeURIComponent(sourcemap.filename)}"`,
    );

    // 创建文件读取流
    const fileStream = fs.createReadStream(absolutePath);

    // 错误处理
    fileStream.on('error', (error) => {
      console.error('文件读取错误:', error);
      if (!res.headersSent) {
        res.status(500).json({ message: '文件读取失败' });
      }
    });

    // 处理客户端断开连接
    res.on('close', () => {
      fileStream.destroy();
    });

    // 流式传输文件
    fileStream.pipe(res).on('error', (error) => {
      console.error('文件传输错误:', error);
      if (!res.headersSent) {
        res.status(500).json({ message: '文件传输失败' });
      }
      fileStream.destroy();
    });
  }
}
